<?php
/**
 * 数据维护 - JBlog
 * 
 * @copyright (c) 2008-2010 JBlog (www.lisijie.org)
 * @author lisijie <lisijie86@gmail.com>
 * @version $Id: mod_data.php 545 2010-07-20 10:07:57Z lisijie86 $
*/

!defined('IN_ADMIN') && exit('Access Denied!');

if ( !is_founder() ) { prompt(__('对不起，你没有权限执行这项操作。')); }

$db_tables = array(
	'jblog_attach' => __('附件表'),
	'jblog_calendar' => __('日历表'),
	'jblog_cate' => __('分类表'),
	'jblog_comment' => __('评论表'),
	'jblog_config' => __('配置信息'),
	'jblog_link' => __('友情链接'),
	'jblog_meta' => __('公用自定义域'),
	'jblog_post' => __('文章表'),
	'jblog_postmeta' => __('文章自定义域'),
	'jblog_search' => __('搜索结果缓存'),
	'jblog_tag' => __('标签表'),
	'jblog_tagpost' => __('标签文章关系表'),
	'jblog_user' => __('用户表')
);

@set_time_limit(0);

empty($ac) && $ac = 'recache';

$tabon[$ac] = ' class="on"';

//刷新缓存
if ( $ac == 'recache') {
	
	if ( $do == 'recache' ) {
		recache();
		prompt(__('成功刷新缓存。'));
	} elseif ( $do == 'clearcachepage') {
		@remove_dir(DATA_ROOT.'page');
		prompt(__('成功删除所有缓存页面。'));
	}
	
//重灌日历
} elseif ( $ac == 'recalendar' ) {
	
	if ( $do == 'exec' ) {
		$db->query("TRUNCATE TABLE ".tname('calendar')."");
		$sql = "SELECT id,dateline FROM ".tname('post')." WHERE `type` = 'blog' AND `status` = '1' ORDER BY dateline ASC";
		$query = $db->query($sql);
		while ($row = $db->fetch_array($query)) {
			$data = array(
				'yearmonth' => get_date($row['dateline'],'Ym'),
				'day' => get_date($row['dateline'],'j'),
				'postid' => $row['id'],
			);
			$db->insert('calendar', $data);
		}
		prompt(__('日历重建完成。'));
	}

//数据表维护	
} elseif ( $ac == 'dbop' ) {
	
	if ( check_submit('dosubmit') ) {
		if ( $_POST['id'] ) {
			$tables = implode(',', $_POST['id']);
			if ( $do == 'repair' ) {
				$query = $db->query("REPAIR TABLE {$tables}");
			} elseif ( $do == 'optimize' ) {
				$query = $db->query("OPTIMIZE TABLE {$tables}");
			}
			$msg = __('成功完成数据表维护：').'<ul>';
			while ( $row = $db->fetch_array($query) ) {
				$tbname = substr(strrchr($row['Table'],'.'),1);
				$msg .= "<li><b>{$tbname}</b> : {$row['Msg_text']}</li>";
			}
			$msg .= '</ul>';
			prompt($msg,'?mod=data&ac=dbop');
		} else {
			prompt(__('请选择要操作的数据表。'), '?mod=data&ac=dbop');
		}
	}

	$tables = array();
	$total_size = 0;
	$query = $db->query("SHOW TABLE STATUS");
	while ( $row = $db->fetch_array($query) ) {
		$tbname = preg_replace('/^'.DB_TABLEPRE.'/', 'jblog_', $row['Name']);
		if ( array_key_exists($tbname, $db_tables) ) {
			$tables[] = array(
				'name' => $row['Name'],
				'use'  => $db_tables[$tbname],
				'engine' => $row['Engine'],
				'rows' => $row['Rows'],
				'data_length' => sizecount($row['Data_length']),
				'index_length' => sizecount($row['Index_length']),
				'data_free' => sizecount($row['Data_free']),
				'size' => sizecount($row['Data_length']+$row['Index_length']),
			);
			$total_size += $row['Data_length']+$row['Index_length'];
		}
	}
	$total_size = sizecount($total_size);

//数据导出
} elseif ( $ac == 'export' ) {
	
	if ( getGP('dosubmit') == 'yes' ) {
		
		initGP(array('bakdir','baktablestr','sizelimit','step','tableid','start','filepre','type'));
		if ( !$baktablestr ) {
			$baktables = (array)$_GET['id'];
			$baktablestr = implode('|', $baktables);
		} else {
			$baktables = explode('|', $baktablestr);
		}
		empty($baktables) && bakmsg(__('请选择要导出的数据表'));

		$sizelimit = intval($sizelimit) ? intval($sizelimit) : 2048;
		!$step && $step = 0;
		!$tableid && $tableid = 0;
		!$start && $start = 0;
		if ( empty($bakdir) ) {
			$bakdir = get_date(NOW,'ymd').'_'.substr(md5(random(10).NOW),-8);
			make_dir(DATA_ROOT.'backup/'.$bakdir);
		}
		//导出到SQL
		if ( $type == 'sql' ) {
			$db->query('SET SQL_QUOTE_SHOW_CREATE=0');
			$bakcontent = "# JBlog Backup File\n".
					   "# Volume: $step\n".
					   "# Version: JBLOG ".JBLOG_VERSION."\n".
					   "# Time: ".get_date(NOW,'Y-m-d H:i')."\n".
				       "# URL: http://www.lisijie.org\n".
					   "#--------------------------------------\n\n";
			if ( !$step ) {
				$filepre = 'jblog_'.substr(md5(random(10).NOW),0,8);
				$bakcontent .= baktable();
			} else {
				$bakcontent .= bakdata();
			}
			$bakfile = DATA_ROOT.'backup/'.$bakdir.'/'.$filepre.'_'.$step.'.sql';
			file_put_contents($bakfile, $bakcontent);
			$step++;
		//导出到XML
		} elseif ( $type == 'xml' ) {
			$table = str_replace(DB_TABLEPRE, '', $baktables[$tableid]);
			$bakfile = DATA_ROOT.'backup/'.$bakdir.'/jblog_'.$table.'_'.$step.'.xml';
			$bakcontent = "<?"."xml version=\"1.0\" encoding=\"utf-8\""."?>\n".
			"<!--\n".
			"# JBlog Backup File\n".
			"# Volume: $step\n".
			"# Version: JBLOG ".JBLOG_VERSION."\n".
			"# Time: ".get_date(NOW,'Y-m-d H:i')."\n".
			"# URL: http://www.lisijie.org\n".
			"-->\n\n<root>\n";
			if ( !$step ) {
				$filepre = 'jblog_'.substr(md5(random(10).NOW),0,8);
			}
			$bakcontent .= bakdata();
			$bakcontent .= "</root>";
			$bakfile = DATA_ROOT.'backup/'.$bakdir.'/'.$filepre.'_'.$step.'.xml';
			file_put_contents($bakfile, $bakcontent);
			$step++;		
		}
		$jumpurl = "admin.php?mod=data&ac=export&dosubmit=yes&type={$type}&bakdir={$bakdir}&sizelimit={$sizelimit}&step={$step}&baktablestr={$baktablestr}&tableid={$tableid}&start={$start}&filepre={$filepre}";
		if ( $tableid >= count($baktables) ) {
			bakmsg(__('所有数据备份完成，共计<b>%s</b>卷，本次备份目录：data/backup/%s', $step, $bakdir), '');
		} else {
			bakmsg(__('分卷<b>%s</b>备份完成，文件名为 %s，正在进行下一分卷备份...', $step-1, str_replace(DATA_ROOT,'',$bakfile)), $jumpurl);
		}
		
	} else {

		make_dir(DATA_ROOT.'backup');

		$tables = array();
		$total_size = 0;
		$query = $db->query("SHOW TABLE STATUS");
		while ( $row = $db->fetch_array($query) ) {
			$tbname = preg_replace('/^'.DB_TABLEPRE.'/', 'jblog_', $row['Name']);
			if ( array_key_exists($tbname, $db_tables) ) {
				$tables[] = array(
					'name' => $row['Name'],
					'use'  => $db_tables[$tbname],
					'rows' => $row['Rows'],
					'size' => sizecount($row['Data_length']+$row['Index_length']),
				);
				$total_size += $row['Data_length']+$row['Index_length'];
			}
		}
		$total_size = sizecount($total_size);		
	}

//备份列表	
} elseif ( $ac == 'baklist' ) {
	
	$result = array();
	$bakdir = DATA_ROOT.'backup';
	if ( !is_dir(DATA_ROOT.'backup') ) {
		make_dir(DATA_ROOT.'backup');
	}
	$dir = dir($bakdir);
	while ( false !== ($entry = $dir->read())) {
		if ( $entry != '.' && $entry != '..' ) {
			$path = $bakdir.'/'.$entry;
			if ( is_dir($path) ) {
				$bak = dir($path);
				while ( false !== ($file = $bak->read()) ) {
					if ( preg_match("/^jblog_(.*)_0.(sql|xml)$/i", $file, $matches) ) {
						$fp = fopen($path.'/'.$file,'rb');
						$info = fread($fp, 255);
						fclose($fp);
						preg_match('/# Version: JBLOG (.*)/', $info, $version);
						preg_match('/# Time: (.*)/', $info, $time);
						$version = $version[1];
						$time = $time[1];
						$result[] = array(
						'dir' => $entry,
						'path' => 'data/backup/'.$entry,
						'type' => strtoupper($matches[2]),
						'version' => trim($version),
						'time' => trim($time),
						);
						break;
					}
				}
				$bak->close();
			}
		}
	}
	$dir->close();

//数据导入
} elseif ( $ac == 'import' ) {
	
	initGP(array('bakdir','dosubmit'));
	if ( !eregi('^[0-9a-z_]+$', $bakdir) ) {
		prompt(__('备份目录<b>%s</b>不合法。',$bakdir));
	}
	if ( $dosubmit == 'yes' ) {
		initGP(array('volume','filepre','count','type'));
		$volume = (int)$volume;
		if ( $type == 'SQL' ) {
			!$volume && $volume = 1; //不导入表结构文件
			$bakfile = DATA_ROOT."backup/{$bakdir}/jblog_{$filepre}_{$volume}.sql";
		} elseif ( $type == 'XML' ) {
			$bakfile = DATA_ROOT."backup/{$bakdir}/jblog_{$filepre}_{$volume}.xml";
		}
		if ( $volume >= $count ) {
			bakmsg(__('所有数据导入完成，共计 <b>%d</b> 卷。', $volume));
		} elseif ( file_exists($bakfile) ) {
			if ( $type == 'SQL' ) {
				bakindata($bakfile);
			} elseif ( $type == 'XML' ) {
				$content = file_get_contents($bakfile);
				$data = xml2array($content);
				foreach ( $data as $table => $rows ) {
					$rows = $rows['row'];
					foreach ( $rows as $row ) {
						$insert = array();
						foreach ( $row as $key => $val ) {
							$val = empty($val) ? '' : base64_decode($val);
							$insert[$key] = add_slashes($val);
						}
						$db->insert($table, $insert, true);
					}
				}			
			}
			$volume ++;
			$jumpurl = "admin.php?mod=data&ac=import&dosubmit=yes&bakdir={$bakdir}&volume={$volume}&filepre={$filepre}&count={$count}";
			bakmsg(__('分卷<b>%d</b>导入完成，正在导入下一分卷...', $volume-1), $jumpurl);
		}
		die;
	} else {
		$tabon['baklist'] = ' class="on"';
		$result = array('volume'=>0,'dir'=>'./data/backup/'.$bakdir.'/');
		$path = DATA_ROOT.'backup/'.$bakdir;
		$dir = dir($path);
		while ( false !== ( $file = $dir->read()) ) {
			if ( preg_match('/^jblog_(.*)_([0-9]+).(sql|xml)$/i', $file, $matches) ) {
				if ( $matches[2] == 0 ) {
					$fp = fopen($path.'/'.$file,'rb');
					$info = fread($fp, 200);
					fclose($fp);
					preg_match('/# Version: JBLOG (.*)/', $info, $version);
					preg_match('/# Time: (.*)/', $info, $time);
					$version = $version[1];
					$time = $time[1];
					$result['filepre'] = $matches[1];
					$result['version'] = trim($version);
					$result['time'] = trim($time);
					$result['type'] = strtoupper($matches[3]);
					$result['volume'] ++;
				} else {
					$result['volume'] ++;
				}
			}
		}
		$dir->close();
	}

//删除备份
} elseif ( $ac == 'bakdel' ) {
	
	$bakarr = getGP('id','P','array');
	if ( empty($bakarr) ) prompt(__('请选中要删除的备份目录。')); 
	foreach ( $bakarr as $val ) {
		if ( strpos($val, '..') === false ) {
			if ( is_dir(DATA_ROOT.'backup/'.$val) ) {
				remove_dir(DATA_ROOT.'backup/'.$val);
			}
		}
	}
	prompt(__('成功删除选中的备份目录。'), 'admin.php?mod=data&ac=baklist');

//其他数据文件导入
} elseif ( $ac == 'import_file' ) {

	initGP('type');
	require JBLOG_INC.'class_upload.php';
	$upload = new Upload();
	$upload->allowtypes = array('xml');
	$file = $upload->execute('attach');
	if ( empty($file) ) {
		redirect('?mod=data&ac=baklist');
	}
	$file = $file[0];
	if ( $file['err'] ) {
		prompt($file['errmsg'],'?mod=data&ac=baklist');
	} else {
		if ( $type == 'xml' ) {
			$content = file_get_contents($file['path']);
			$data = xml2array($content);
			foreach ( $data as $table => $rows ) {
				$rows = $rows['row'];
				foreach ( $rows as $row ) {
					$insert = array();
					foreach ( $row as $key => $val ) {
						$val = empty($val) ? '' : base64_decode($val);
						$insert[$key] = add_slashes($val);
					}
					$db->insert($table, $insert, true);
				}
			} 
			@unlink($file['path']);
		}
	}
	prompt(__('数据导入成功。'),'?mod=data&ac=baklist');
	
}

function baktable() {
	global $db,$baktables;
	$sql = '';
	foreach ( $baktables as $table ) {
		$row = $db->fetch_one_array("SHOW CREATE TABLE $table");
		$sql .= "DROP TABLE IF EXISTS $table;\n\n";
		$sql .= $row['Create Table'].";\n\n";
	}
	return $sql;
}
function bakdata() {
	global $db,$baktables,$tableid,$sizelimit,$start,$type;
	$count = count($baktables);
	$bakdata = '';
	for ( $i=$tableid; $i<$count; $i++ ) {
		$tableid = $i;
		$stop = $finish = false;
		$status = $db->fetch_one_array("SHOW TABLE STATUS LIKE '$baktables[$i]'");
		$rows = $status['Rows'];
		if ( $type == 'xml' ) {
			$table = str_replace(DB_TABLEPRE, '', $baktables[$i]);
			$bakdata .= "<$table>\n";
		}
		while ( !$stop ) {
			$query = $db->query("SELECT * FROM `".$baktables[$i]."` LIMIT $start, 5000");
			if ( $type == 'sql' ) {
				$fields = $db->num_fields($query);
				while ( $row = $db->fetch_array($query,MYSQL_NUM) ) {
					$start ++;
					$bakdata .= "INSERT INTO $baktables[$i] VALUES ('".mysql_escape_string($row[0])."'";
					for ( $j=1; $j<$fields; $j++) {
						$bakdata .= " ,'".mysql_escape_string($row[$j])."'";
					}
					$bakdata .= ");\n";
					if ( strlen($bakdata) > ($sizelimit * 1000) ) {
						$stop = true;
						break;
					}
				}
			} elseif ( $type == 'xml' ) {
				while ( $row = $db->fetch_array($query) ) {
					$start ++;
					$bakdata .= "\t<row>\n";
					foreach ( $row as $key => $val ) {
						$bakdata .= "\t\t<{$key}>".base64_encode($val)."</{$key}>\n";
					}
					$bakdata .= "\t</row>\n";					
					if ( strlen($bakdata) > ($sizelimit * 1000) ) {
						$stop = true;
						break;
					}
				}			
			}
			$db->free_result($query);
			if ( $start >= $rows ) {
				$stop = true;
				$finish = true;
				$start = 0;
			}
		}
		if ( $type == 'xml' ) {
			$bakdata .= "</$table>\n";
		}
		if ( strlen($bakdata) > ($sizelimit * 1000) ) {
			break;
		}
		if ( $finish && $tableid == $count - 1 ) $tableid ++;
	}
	return $bakdata;
}
function bakindata($file) {
	global $db;
	$baksql = file($file);
	foreach ($baksql as $key => $val) {
		$val = trim($val);
		if ( empty($val) || substr($val,0,1) == '#') continue;
		if ( eregi('\;$', $val) ) {
			$query .= $val;
			if ( eregi('^CREATE',$query) ) {
				$query = substr($query, 0, strrpos($query, ')')+1);
				if( $db->version() > '4.1' ){
					$query .= 'ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;';
				} else {
					$query .= 'TYPE=MyISAM;';
				}
			} elseif ( eregi('^INSERT', $query) ) {
				$query = 'REPLACE '.substr($query,6);
			}
			$db->query($query);
			$query = '';
		} else {
			$query .= $val;
		}
	}	
}

function bakmsg($message, $url = null) {
	$jump = '';
	if ( $url ) {
		$jump = '<script type="text/javascript">setTimeout("window.location.href=\''.$url.'\'",500);</script>';
	}
	echo <<<EOT
	<html>
	<head></head>
	<body>
	<p>{$message}</p>
	{$jump}
	</body>
	</html>
EOT;
	exit;
}

include admin_tpl('data');
?>